package cn.spream.jstudy.bytecode;

import javax.tools.*;
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Arrays;

/**
 * java字节码操作
 * Created by IntelliJ IDEA.
 * User: cn.spream
 * Date: 12-6-12
 * Time: 下午3:02
 * To change this template use File | Settings | File Templates.
 */
public class JavaByteCodeHandle {

    public static boolean compile(String classString, String className) throws Exception{
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
        StringSourceJavaObject sourceObject = new JavaByteCodeHandle.StringSourceJavaObject(className, classString);
        Iterable< ? extends JavaFileObject> fileObjects = Arrays.asList(sourceObject);
        JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, null, null, null, fileObjects);
        return task.call();
    }

    private static double calculate(String expr) throws Exception{
        String className = "CalculatorMain";
        String methodName = "calculate";
        String source = "public class " + className + " { public static double " + methodName + "() { return " + expr + "; } }";
        boolean result = JavaByteCodeHandle.compile(source, className);
        if (result) {
            // 获得loader
            ClassLoader loader = JavaByteCodeHandle.class.getClassLoader();
            Class<?> clazz = loader.loadClass(className);
            Method method = clazz.getMethod(methodName, new Class<?>[] {});
            Object value = method.invoke(null, new Object[] {});
            return (Double) value;
        }else{
            throw new RuntimeException("错误的表达式");
        }
    }

    private static class StringSourceJavaObject extends SimpleJavaFileObject {
        private String content = null;
        public StringSourceJavaObject(String name, String content) throws URISyntaxException {
            super(URI.create("string:///" + name.replace('.', '/') +
                    Kind.SOURCE.extension), Kind.SOURCE);
            this.content = content;
        }
        public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
            return content;
        }
    }

    public static void main(String[] args) throws Exception{
//        String source = "public class TestJavaCompiler { public static void main(String[] args) {System.out.println(\"Hello World!\");} }";
//        boolean result = JavaByteCodeHandle.compile(source, "TestJavaCompiler");
//        if (result) {
//            System.out.println("编译成功。");
//        }

        String expr = "(3+4)*7-10";
        double result = JavaByteCodeHandle.calculate(expr);
        System.out.println(expr + "=" + result);
    }
}